using System;
using System.IO;

using System.Collections.Generic;


namespace HappyTemplate
{
	class Character
	{
		readonly int _lineNo = 1;
		readonly int _columnNo = 1;
		readonly string _fileName;
		readonly char _c;

		public Character(int lineNo, int columNo, string filename, char c)
		{
			_lineNo = lineNo;
			_columnNo = columNo;
			_fileName = filename;
			_c = c;
		}

		public int LineNo
		{
			get { return _lineNo; }
		}

		public int ColumnNo
		{
			get { return _columnNo; }
		}

		public string FileName
		{
			get { return _fileName; }
		}

		public char C
		{
			get { return _c; }
		}
	}

	class InputReader
	{
		readonly string _fileName;
		readonly TextReader _reader;
		int _lineNo = 1;
		int _columnNo = 1;
		bool _eof;
		readonly List<Character> _queue = new List<Character>();

		public bool Eof 
		{ 
			get
			{
				//if(_eof == false && _queue.Count > 0 && this.Peek(0) == 0xFFFF)
				//    _eof = true;
					
				//return _eof && _queue.Count == 0;
				return _eof;
			} 
		}

		public InputReader(TextReader reader, string filename)
		{
			_reader = reader;
			_fileName = filename;
		}

		public SourceLocation CurrentLocation
		{
			get
			{
				if(_queue.Count == 0)
					return new SourceLocation(_lineNo, _columnNo, _fileName);
				else
				{
					Character c = _queue[0];
					return new SourceLocation(c.LineNo, c.ColumnNo, c.FileName);
				}
			}
		}

		public char Read()
		{
			char retval;
			if(_queue.Count == 0)
				retval = Extract().C;
			else
			{
				Character r = _queue[0];
				_queue.RemoveAt(0);
				retval = r.C;
			}

			if(this.Peek(0) == 0xFFFF)
				_eof = true;

			return retval;
		}

		private Character Extract()
		{
			int readChar = _reader.Read();

			Character retval = new Character(_lineNo, _columnNo, _fileName, (char)readChar);

			if (retval.C == '\n')
			{
				_lineNo++;
				_columnNo = 1;
			}
			else
				_columnNo++;

			return retval;
		}

		public char Peek()
		{
			return Peek(0);
		}

		public char Peek(int ahead)
		{
			while(_queue.Count <= ahead)
				_queue.Add(Extract());

			return _queue[ahead].C;
		}

		public bool PeekIsWhite()
		{
			return Char.IsWhiteSpace(Peek());
		}

		public bool PeekIsNumber()
		{
			return Char.IsNumber(Peek());
		}
	}
}
